/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package cn.ac.iie.di.ban.news.server.util;

import java.util.Iterator;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.apache.log4j.Logger;

/**
 *
 * @author zwlin
 */
public class HostInfoKeeper {

	private static Logger logger = Logger.getLogger(HostInfoKeeper.class);

	private long delta;

	public HostInfoKeeper(long maxDelaySecond) {
		delta = maxDelaySecond * 1000;
		testHosts = new ConcurrentHashMap<>();
		testLock = new ReentrantReadWriteLock();
		testHostLines = "";
		onlineHosts = new ConcurrentHashMap<>();
		onlineLock = new ReentrantReadWriteLock();
		onlineHostLines = "";
		isActivated = false;
		checkTimer = new Timer("HostInfoCheckTimer");
	}

	public void start() {
		checkTimer.schedule(new TimerTask() {
			@Override
			public void run() {
				check();
			}
		}, 0, delta / 2);
		isActivated = true;
	}

	public void stop() {
		isActivated = false;
		checkTimer.cancel();
	}

	//tag
	private boolean isActivated;
	//test and online
	private final ConcurrentHashMap<String, Long> testHosts;
	private final ReentrantReadWriteLock testLock;
	private String testHostLines;
	private final ConcurrentHashMap<String, Long> onlineHosts;
	private final ReentrantReadWriteLock onlineLock;
	private String onlineHostLines;

	//check timer
	private Timer checkTimer;

	public void regTestHost(String host) {
		if (!isActivated) {
			return;
		}
		testLock.writeLock().lock();
		try {
			if (!testHosts.containsKey(host)) {
				if (testHostLines.length() > 0) {
					testHostLines += "\n";
				}
				testHostLines += host;
			}
			testHosts.put(host, System.currentTimeMillis());
		} finally {
			testLock.writeLock().unlock();
		}
		logger.debug("testHostLines: " + testHostLines);
	}

	public void regOnlineHost(String host) {
		if (!isActivated) {
			return;
		}
		onlineLock.writeLock().lock();
		try {
			if (!onlineHosts.containsKey(host)) {
				if (onlineHostLines.length() > 0) {
					testHostLines += "\n";
				}
				onlineHostLines += host;
			}
			onlineHosts.put(host, System.currentTimeMillis());
		} finally {
			onlineLock.writeLock().unlock();
		}
		logger.debug("onlineHostLines: " + onlineHostLines);
	}

	private void check() {
		if (!isActivated) {
			return;
		}
		//minimum time not delete
		long min = System.currentTimeMillis() - delta;
		//if need to rebuild hostline,no remove means no need
		boolean needRebuild = false;
		//hostline builder
		StringBuilder hostline = new StringBuilder();
		//for test hosts
		testLock.writeLock().lock();
		try {
			//get iterator
			Iterator<Map.Entry<String, Long>> itr = testHosts.entrySet().iterator();
			//each host entry
			while (itr.hasNext()) {
				Map.Entry<String, Long> h = itr.next();
				//last reg time less than min time, remove host and need rebuild
				if (h.getValue() < min) {
					needRebuild = true;
					itr.remove();
				}
			}
			//rebuild host line if need
			if (needRebuild) {
				for (String host : testHosts.keySet()) {
					if (hostline.length() > 0) {
						hostline.append("\n");
					}
					hostline.append(host);
				}
				testHostLines = hostline.toString();
			}
		} finally {
			testLock.writeLock().unlock();
		}
		logger.debug("testHostLines: " + testHostLines);
		//reset rebuild tag and host line builder
		needRebuild = false;
		hostline.delete(0, hostline.length());
		//for online hosts
		onlineLock.writeLock().lock();
		try {
			Iterator<Map.Entry<String, Long>> itr = onlineHosts.entrySet().iterator();
			while (itr.hasNext()) {
				Map.Entry<String, Long> h = itr.next();
				if (h.getValue() < min) {
					needRebuild = true;
					itr.remove();
				}
			}
			if (needRebuild) {
				for (String host : onlineHosts.keySet()) {
					if (hostline.length() > 0) {
						hostline.append("\n");
					}
					hostline.append(host);
				}
				onlineHostLines = hostline.toString();
			}
		} finally {
			onlineLock.writeLock().unlock();
		}
		logger.debug("onlineHostLines: " + onlineHostLines);
	}

	public String getTestHostLines() {
		if (!isActivated) {
			return null;
		}
		return testHostLines;
	}

	public String getOnlineHostLines() {
		if (!isActivated) {
			return null;
		}
		return onlineHostLines;
	}
}
